package com.scut.filedownloader.core.interact;

import com.scut.filedownloader.core.Downloader;

/**
 * 抽象的下载监视器对象，采用了被动式监听的方法，实时汇报进度的功能，因此对于使用了download服务的那一方，就需要协同于预先设定的交互协议。
 * 在这个类中实现了一些ProgressMonitor<K,V>中的接口，在使用时可以省去重复的覆写实现，下面是关于各个方法的描述。
 */
abstract public class AbsDownloadMonitor implements ProgressMonitor<Integer,Long> {

    protected boolean interrupt=false; //pause signal
    protected boolean cancel=false;  //取消信号
    protected ProgressState state=ProgressState.READY;
    protected long totalLength=0L;


    public AbsDownloadMonitor(){
        state=ProgressState.READY;
    }
    /**
     * 去除auto-box化，不使用该方法
     * @param key
     * @param value
     */
    @Override @Deprecated
    public void onProgress(Integer key, Long value) {
        onProgress(key.intValue(),value.longValue());
    }

    /**
     * 每当下载进程完成固定长度数据的传输后，会调用该方法,汇报当前分块的下载进度
     * @param key 分块的编号
     * @param value 分块内已经下载的字节数
     */
    abstract public void onProgress(int key, long value);


    /**
     * 当所有下载子进程成功完成下载任务的时候，会调用该方法，表示任务完成，如果有子任务失败了或者手动终止了
     * 会调用onStop()
     */
    @Override
    public void onFinished() {
        state=ProgressState.COMPLETED;
    }

    /**
     * 下载线程启动时会调用该方法
     */
    @Override
    public void onStart() {
        state= ProgressState.GOING;
    }

    /**
     * 任务未完成，但下载线程就要结束时，会调用该方法，并通过{@linkplain com.scut.filedownloader.core.interact.ProgressMonitor.ProgressState  state}
     * 参数表示其终止时所处的状态，可用状态包括
     * 1. FAILED 这是最常见的状态，大多数终止都以失败状态结束
     * 2. ABORTED 表示这是由于监视器对象cancelSignal()调用返回true导致的，表示任务被丢弃
     *
     */
    @Override
    public void onStop(ProgressState state) {
        this.state=state;
    }

    /**
     * 子类一般无需直接修改该方法，interruptSignal()是供下载线程调用检测是否有暂停命令发下来的。
     * @return true表示有暂停信号
     */
    @Override
    public boolean interruptSignal() {
        return interrupt;
    }

    /**
     * 用于检测是否有取消信号产生
     * @return true表示任务被用户取消了
     */
    @Override
    public boolean cancelSignal() {
        return cancel;
    }

    /**
     * 这有点类似于Thread.interrupted(),但这个方法更简单，只是将中断状态来回切换。
     */
    public void interrupt(){
        interrupt=!interrupt;
    }

    /**
     * 发出取消信号，需要注意的是，这只是个hint提示，下载线程是根据其最后一次对cancelsignal()调用结果来决定
     * 是否取消任务的，一般来说，在线程处于忙等暂停阶段时，该方法发出的提示都能使到任务终止。但对于其它情况,如果线程
     * 执行到一个不会再继续调用cancelSignal()的阶段后，线程就是处于任务完成阶段了，这是无论是取消还是不取消，差别就只在于
     * 下载的临时文件是否要被删除的差别，这里Downloader没有对下载的文件进行删除的操作，因为从设计上来来说这是属于
     * Downloader职责范围之外的工作。
     */
    public void cancel(){
        cancel=true;
    }

    /**
     * 监视器对象接受错误信息，进度消息的接口，{@linkplain Downloader.MessageCode messageCode}定义了消息码的类型
     * @param messageCode 消息码，监视器可以根据对应的消息码做出对应的ui显示操作
     * @param msg 消息主体
     */
    abstract public void receiveMessage(final Downloader.MessageCode messageCode,final String msg);

    /**
     * 类似于{@link #receiveMessage(Downloader.MessageCode, int)}, 消息主体变为了整数
     * 这个方法主要是通告http连接结果的消息码和http连接的重试次数
     * @param messageCode 消息码类型
     * @param varInt 整数类型的消息，当消息码为{@linkplain com.scut.filedownloader.core.Downloader.MessageCode NOTICE_HTTP_RESPONSE_CODE}时
     *               值为http协议的消息码，消息码为{@linkplain com.scut.filedownloader.core.Downloader.MessageCode NOTICE_HTTP_RECONNECT} 时， varInt为
     *               http连接的重试次数
     */
    abstract public void receiveMessage(final Downloader.MessageCode messageCode,final int varInt);
}
